package com.android.common.view;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.android.common.R;
import com.android.common.util.ToastUtil;

/**
 * 自定义ListView，支持顶部下拉刷新，底部自动加载更多
 * 
 */
public class PullListView extends ListView implements OnScrollListener {
	private static String TAG = "PullListView";

	private final static int PULL_STATUS_NONE = 0; // 正常状态
	private final static int PULL_STATUS_DOWN = 1; // 进入下拉刷新状态
	private final static int PULL_STATUS_RELEASE = 2; // 进入松手刷新状态
	private final static int PULL_STATUS_REFRESHING = 3; // 松手后反弹和加载状态

	private final static int HANDLER_REFRESH_BACKING = 0; // 反弹中
	private final static int HANDLER_REFRESH_REFRESHING = 1; // 反弹结束，达到刷新界限
	private final static int HANDLER_REFRESH_RETURN = 2; // 没有达到刷新界限，返回正常状态
	private final static int HANDLER_REFRESH_REFRESHED = 3; // 刷新数据后台请求结束
	private final static int HANDLER_MORE_LOADED = 6; // 底部加载更多数据后台请求结束

	private final static int REQUEST_STATUS_NONE = 0; // 当前没有任何操作
	private final static int REQUEST_STATUS_REFRESH = 1; // 当前正在进行刷新操作
	private final static int REQUEST_STATUS_MORE = 2; // 当前正在进行加载更多操作

	private final static float PADDING_TOP_PULL_RELEASE_RATE = 0.75f; // paddingTop每次缩减比率
	private final static float PADDING_TOP_PULL_DOWN_RATE = 0.3f; // paddingTop相对于手指滑动距离比率
	private final static int HEADER_VIEW_HEIGHT_THROTTLE = 20; // 下拉到一定阀值进入松手提示
	private final static String TAG_FOOTER_VIEW = "TAG_FOOTER_VIEW";

	private int mCurrentScrollState; // 记录当前onScroll滚动状态
	private int mCurrentPullState = PULL_STATUS_NONE; // 当前手指刷新状态
	private int mCurrentReqestStatus = REQUEST_STATUS_NONE; // 当前正在后台请求数据的类别，顶部刷新和底部加载更多共用，同一时刻只能有一个后台线程运行

	private SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat(
			"MM-dd HH:mm"); // 日期时间格式化工具类

	private float mFingerDownY; // 手指首次按下时的Y坐标值
	private float mFingerMoveY; // 手指滑动过程中的Y坐标值，随手指滑动而变化

	private int mHeaderHeight; // headerView的高度
	private int mCurrentHeaderPaddingTop; // headerView的paddingTop值，用于计算需要缩减次数
	private boolean mGotoLoadingMore = false; // 是否达到底部加载更多的条件

	// header中相关的View
	private LinearLayout mHeaderLinearLayoutContainer = null;// 只是为了GONE起效
	private LinearLayout mHeaderLinearLayout = null;
	private TextView mHeaderTextView = null;
	private TextView mHeaderUpdateText = null;
	private ImageView mHeaderPullDownImageView = null;
	private ProgressBar mHeaderProgressBar = null;

	// footer中相关的View
	private LinearLayout mFooterLinearLayout = null;

	// 以下为调用方需要设置的属性
	private OnPullListener mOnPullListener = null; // 回调接口
	private Date mLastUpdateTime = null; // 用于显示上次更新时间，每次刷新成功后都需要设置
	private boolean mEnablePullTopRefresh = true; // 是否开启列表顶部下拉刷新支持

	public PullListView(Context context) {
		this(context, null);
	}

	public PullListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}

	public void setLastUpdateTime(Date lastUpdateTime) {
		this.mLastUpdateTime = lastUpdateTime;
	}

	public void setFooterViewVisibility(int visibility) {
		mFooterLinearLayout.setVisibility(visibility);
		if (visibility != View.VISIBLE) {
			setFooterDividersEnabled(false);
		}
	}

	@Override
	public void setSelection(int position) {
		Log.i(TAG, "setSelection position=" + position + ",footer.top="
				+ mFooterLinearLayout.getTop() + ",getHeight=" + getHeight());
		if (mFooterLinearLayout.getTop() < getHeight()) {
			mHeaderLinearLayoutContainer.setVisibility(View.GONE);
		} else {
			super.setSelection(position);
		}
	}

	@Override
	public void setAdapter(ListAdapter adapter) {
		if (mEnablePullTopRefresh && indexOfChild(mHeaderLinearLayout) == -1) {
			addHeaderView(mHeaderLinearLayout); // 将向下滑动刷新的视图加入Header
		}
		super.setAdapter(adapter);
	}

	/**
	 * 使用该组件的地方必须设置，否则不会有页面实际效果；
	 * 
	 * @param mOnPullListener
	 */
	public void setOnPullListener(OnPullListener onPullListener) {
		this.mOnPullListener = onPullListener;
		setOnScrollListener(this); // 设置滑动Listener
	}

	public void setEnablePullTopRefresh(boolean enablePullTopRefresh) {
		this.mEnablePullTopRefresh = enablePullTopRefresh;
	}

	void init(final Context context) {
		mHeaderLinearLayout = (LinearLayout) LayoutInflater.from(context)
				.inflate(R.layout.pull_list_header, null);
		mHeaderTextView = (TextView) mHeaderLinearLayout
				.findViewById(R.id.pull_list_header_text);
		mHeaderUpdateText = (TextView) mHeaderLinearLayout
				.findViewById(R.id.pull_list_header_last_update);
		mHeaderPullDownImageView = (ImageView) mHeaderLinearLayout
				.findViewById(R.id.pull_list_header_pull_down);
		mHeaderProgressBar = (ProgressBar) mHeaderLinearLayout
				.findViewById(R.id.pull_list_header_progressbar);
		mHeaderLinearLayoutContainer = (LinearLayout) mHeaderLinearLayout
				.findViewById(R.id.pull_list_header_container);
		mHeaderLinearLayoutContainer.setVisibility(View.GONE);
		// addHeaderView(mHeaderLinearLayout); // 将向下滑动刷新的视图加入Header

		mFooterLinearLayout = (LinearLayout) LayoutInflater.from(context)
				.inflate(R.layout.pull_list_footer, null);
		mFooterLinearLayout.setTag(TAG_FOOTER_VIEW);
		addFooterView(mFooterLinearLayout); // 将向上滑动刷新的视图加入Footer

		measureView(mHeaderLinearLayout); // 模拟计算HeaderView加载后的高度
		mHeaderHeight = mHeaderLinearLayout.getMeasuredHeight();
		Log.i(TAG, "init's mHeaderHeight = " + mHeaderHeight);
	}

	/**
	 * 拦截当前视图的Touch事件，避免向子元素传递事件，直接交由该视图的onTouchEvent处理
	 * 
	 * @return 是否由当前视图处理Touch事件，若为false，则向下传递，
	 *         此时onTouchEvent中无法捕获MotionEvent.ACTION_DOWN
	 */
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		boolean superResult = super.onInterceptTouchEvent(ev);
		Log.i(TAG, "onInterceptTouchEvent 's ACTION = " + ev.getAction()
				+ ", superResult = " + superResult);
		if (ev.getAction() == MotionEvent.ACTION_DOWN
				&& mCurrentPullState == PULL_STATUS_NONE
				&& mEnablePullTopRefresh) {
			mFingerDownY = ev.getY();
			if (this.mLastUpdateTime != null) {
				mHeaderUpdateText.setText(getResources().getString(
						R.string.pull_list_header_refresh_last_update,
						mSimpleDateFormat.format(this.mLastUpdateTime)));
			}
			mHeaderTextView.setText(getContext().getString(
					R.string.pull_list_header_refresh_down));
			mHeaderPullDownImageView
					.setImageResource(R.drawable.pull_list_pull_down);
			setHeaderChildVisibility(View.INVISIBLE, View.VISIBLE);
		}

		if (ev.getAction() == MotionEvent.ACTION_UP
				&& mCurrentScrollState != SCROLL_STATE_IDLE) {
			return true;
		}

		return false;
	}

	/**
	 * 主要用于处理Header顶部自动刷新事件
	 */
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		boolean superResult = super.onTouchEvent(ev);
		if (!mEnablePullTopRefresh) {
			return superResult;
		}
		Log.i(TAG, "onTouchEvent 's ACTION = " + ev.getAction()
				+ ", mCurrentPullState = " + mCurrentPullState);

		switch (ev.getAction()) {
		case MotionEvent.ACTION_MOVE:
			mFingerMoveY = ev.getY();
			int firstVisiblePosition = getFirstVisiblePosition();
			int headerBottom = mHeaderLinearLayout.getBottom(); // headerView的bottom高度
			Log.i(TAG, "onTouchEvent 's ACTION_MOVE headerBottom = "
					+ headerBottom + ",mFingerMoveY=" + mFingerMoveY
					+ ",mFingerDownY=" + mFingerDownY + ",paddingTop="
					+ mHeaderLinearLayout.getPaddingTop());
			if (firstVisiblePosition == 0 && headerBottom >= 0
					&& mFingerMoveY > mFingerDownY + 5) { // 避免点击时出现headerView
				mHeaderLinearLayoutContainer.setVisibility(View.VISIBLE);
				if (headerBottom < mHeaderHeight + HEADER_VIEW_HEIGHT_THROTTLE) {
					// 进入且仅进入下拉刷新状态
					if (mCurrentPullState == PULL_STATUS_NONE) {
						mCurrentPullState = PULL_STATUS_DOWN;
					}
				} else {
					// 下拉达到界限，进入松手刷新状态
					if (mCurrentPullState == PULL_STATUS_DOWN
							|| mCurrentPullState == PULL_STATUS_NONE) {
						mCurrentPullState = PULL_STATUS_RELEASE;
						// mFingerDownY = mFingerMoveY; // 为下拉1/3折扣效果记录开始位置
						mHeaderTextView.setText(getContext().getString(
								R.string.pull_list_header_refresh_up));// 显示松手刷新
						mHeaderPullDownImageView
								.setImageResource(R.drawable.pull_list_release_up);
					}
				}
			} else {
				// 向上滑动，取消刷新操作
				if (mCurrentPullState == PULL_STATUS_DOWN) {
					mCurrentPullState = PULL_STATUS_NONE;
				}
			}
			if (mCurrentPullState == PULL_STATUS_RELEASE
					|| mCurrentPullState == PULL_STATUS_DOWN) {
				// HeaderView的paddingTop设置为滑动高度的1/3
				int paddingTop = (int) ((mFingerMoveY - mFingerDownY) * PADDING_TOP_PULL_DOWN_RATE);
				setHeaderViewPadding(paddingTop);
			}
			break;
		case MotionEvent.ACTION_UP:
			if (mCurrentPullState == PULL_STATUS_RELEASE
					|| mCurrentPullState == PULL_STATUS_DOWN) {
				mFingerDownY = mFingerMoveY; // 记录padding弹回开始位置
				mCurrentHeaderPaddingTop = mHeaderLinearLayout.getPaddingTop();
				new Thread() {
					public void run() {
						Message msg;
						while (mCurrentHeaderPaddingTop > 0) {
							msg = mHandler.obtainMessage();
							msg.what = HANDLER_REFRESH_BACKING;
							mHandler.sendMessage(msg);
							try {
								sleep(10);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
							mCurrentHeaderPaddingTop = (int) (mCurrentHeaderPaddingTop * PADDING_TOP_PULL_RELEASE_RATE);
						}
						msg = mHandler.obtainMessage();
						if (mCurrentPullState == PULL_STATUS_RELEASE) {
							msg.what = HANDLER_REFRESH_REFRESHING;
						} else {
							msg.what = HANDLER_REFRESH_RETURN;
						}
						mHandler.sendMessage(msg);
					};
				}.start();
			}
			break;
		}
		return superResult;
	}

	private Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			Log.i(TAG, "mHandler msg.what=" + msg.what);
			switch (msg.what) {
			case HANDLER_REFRESH_BACKING:
				// headerView的paddingTop每次将为原来的75%
				int paddingTop = (int) (mHeaderLinearLayout.getPaddingTop() * PADDING_TOP_PULL_RELEASE_RATE);
				setHeaderViewPadding(paddingTop);
				break;
			case HANDLER_REFRESH_REFRESHING:
				// 进入正在刷新状态
				Log.i(TAG, "onPull's 正在刷新 ");
				mCurrentPullState = PULL_STATUS_REFRESHING;
				mHeaderTextView.setText(getContext().getString(
						R.string.pull_list_header_refreshing)); // 正在刷新...
				setHeaderChildVisibility(View.VISIBLE, View.INVISIBLE);
				if (mCurrentReqestStatus != REQUEST_STATUS_REFRESH) {
					new Thread() {
						public void run() {
							isNeedWaitForRequestingInbackground(this,
									REQUEST_STATUS_REFRESH);
							if (mOnPullListener != null) {
								Message msg = mHandler.obtainMessage();
								msg.what = HANDLER_REFRESH_REFRESHED;
								msg.obj = mOnPullListener
										.onTopRefreshingInBackground();
								mHandler.sendMessage(msg);
							}
						};
					}.start();
				}
				break;
			case HANDLER_REFRESH_RETURN:
				mCurrentPullState = PULL_STATUS_NONE;
				setHeaderViewPadding(0);
				setSelection(1);
				break;
			case HANDLER_REFRESH_REFRESHED:
				mCurrentPullState = PULL_STATUS_NONE;
				setHeaderViewPadding(0);
				setLastUpdateTime(new Date());
				setFooterViewVisibility(View.VISIBLE);
				if (mOnPullListener != null) {
					showPullMessage(true,
							mOnPullListener.onTopRefreshed(msg.obj));
					mCurrentReqestStatus = REQUEST_STATUS_NONE;
				}
				setSelection(1);
				break;
			case HANDLER_MORE_LOADED:
				if (mOnPullListener != null) {
					showPullMessage(false,
							mOnPullListener.onBottomLoaded(msg.obj));
					mCurrentReqestStatus = REQUEST_STATUS_NONE;
				}
				break;
			default:
				break;
			}
		}
	};

	/**
	 * 主要用于处理Footer底部自动加载更多事件
	 */
	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		Log.i(TAG, "onScroll's firstVisibleItem = " + firstVisibleItem
				+ ", visibleItemCount = " + visibleItemCount
				+ ", totalItemCount = " + totalItemCount
				+ ", mCurrentScrollState = " + mCurrentScrollState
				+ ", mCurrentPullState = " + mCurrentPullState
				+ ", mCurrentReqestStatus = " + mCurrentReqestStatus);

		// 处理列表Footer向上滑动加载更多
		if (totalItemCount == firstVisibleItem + visibleItemCount) {
			mGotoLoadingMore = true;
		} else {
			mGotoLoadingMore = false;
		}
	}

	/**
	 * 主要用于处理Footer底部自动加载更多事件
	 */
	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		mCurrentScrollState = scrollState;
		int firstVisiblePosition = getFirstVisiblePosition();
		int headerBottom = mHeaderLinearLayout.getBottom(); // headerView的bottom高度
		Log.i(TAG, "onScrollStateChanged's scrollState = " + scrollState
				+ ",firstVisiblePosition=" + firstVisiblePosition
				+ ",headerBottom=" + headerBottom);
		// 当滑动结束时根据下拉状态自动对headerView隐藏，主要是应对飞滑自动结束
		if (scrollState == SCROLL_STATE_IDLE && headerBottom > 1
				&& mCurrentPullState == PULL_STATUS_NONE) {
			Message msg = mHandler.obtainMessage();
			msg.what = HANDLER_REFRESH_RETURN;
			mHandler.sendMessage(msg);
		}

		if (mGotoLoadingMore && mCurrentReqestStatus != REQUEST_STATUS_MORE
				&& mFooterLinearLayout.getVisibility() == view.VISIBLE) {
			if (mCurrentReqestStatus != REQUEST_STATUS_NONE) {
				// 此时正在进行顶部刷新后台请求
				String msg = getContext().getString(
						R.string.pull_list_footer_toast_msg_wait);
				ToastUtil.showToast(getContext(), msg);
			}
			// 后台加载任务
			new Thread() {
				public void run() {
					isNeedWaitForRequestingInbackground(this,
							REQUEST_STATUS_MORE);
					if (mOnPullListener != null) {
						Message msg = mHandler.obtainMessage();
						msg.what = HANDLER_MORE_LOADED;
						msg.obj = mOnPullListener.onBottomLoadingInBackground();
						mHandler.sendMessage(msg);
					}
				};
			}.start();
		}
	}

	/**
	 * 判断当前线程是否需要等待
	 * 
	 * @param thread
	 */
	private void isNeedWaitForRequestingInbackground(Thread thread,
			int pendingRequest) {
		if (mCurrentReqestStatus == REQUEST_STATUS_NONE) {
			mCurrentReqestStatus = pendingRequest;
		} else {
			while (mCurrentReqestStatus != REQUEST_STATUS_NONE) {
				try {
					thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				mCurrentReqestStatus = pendingRequest;
			}
		}
	}

	/**
	 * 模拟加载headerView，以便计算实际高度
	 * 
	 * @param child
	 */
	private void measureView(View child) {
		ViewGroup.LayoutParams p = child.getLayoutParams();
		if (p == null) {
			p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
					ViewGroup.LayoutParams.WRAP_CONTENT);
		}

		int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);
		int lpHeight = p.height;
		int childHeightSpec;
		if (lpHeight > 0) {
			childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
					MeasureSpec.EXACTLY);
		} else {
			childHeightSpec = MeasureSpec.makeMeasureSpec(0,
					MeasureSpec.UNSPECIFIED);
		}
		child.measure(childWidthSpec, childHeightSpec);
	}

	/**
	 * 数据加载完成后显示提示文案
	 * 
	 * @param isHeader
	 * @param msg
	 */
	private void showPullMessage(boolean isHeader, String msg) {
		// if (isHeader || (!isHeader && !StringUtil.isEmpty(msg))) {
		// if (StringUtil.isEmpty(msg)) {
		// if (isHeader) {
		// msg = getContext().getString(
		// R.string.pull_list_header_toast_msg);
		// } else {
		// msg = getContext().getString(
		// R.string.pull_list_footer_toast_msg);
		// }
		// }
		// Toast toast = Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT);
		// toast.setGravity(Gravity.CENTER, 0, 0);
		// toast.show();
		// }
	}

	/**
	 * 设置headerView中子元素的可视状态View.VISIBLE/View.INVISIBLE/View.GONE
	 * 
	 * @param processBarVisibility
	 * @param pullDownImageVisibility
	 */
	private void setHeaderChildVisibility(int processBarVisibility,
			int pullDownImageVisibility) {
		mHeaderProgressBar.setVisibility(processBarVisibility);
		mHeaderPullDownImageView.setVisibility(pullDownImageVisibility);
	}

	/**
	 * 设置headerView的padding，其实只改变paddingTop
	 * 
	 * @param paddingTop
	 */
	private void setHeaderViewPadding(int paddingTop) {
		mHeaderLinearLayout.setPadding(mHeaderLinearLayout.getPaddingLeft(),
				paddingTop, mHeaderLinearLayout.getPaddingRight(),
				mHeaderLinearLayout.getPaddingBottom());
	}

	@Override
	public void setOnItemClickListener(OnItemClickListener listener) {
		super.setOnItemClickListener(new ProxyOnItemClickListener(listener));
	}

	private class ProxyOnItemClickListener implements OnItemClickListener {

		private OnItemClickListener mOnItemClickListener;

		public ProxyOnItemClickListener(OnItemClickListener listener) {
			this.mOnItemClickListener = listener;
		}

		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position,
				long id) {
			if (parent.getItemAtPosition(position) != null
					&& !TAG_FOOTER_VIEW.equals(view.getTag())) {
				mOnItemClickListener.onItemClick(parent, view, position, id);
			}
		}

	}

}
